#include "EventLoop.h"
#include "Logger.h"
#include "Poller.h"
#include "Channel.h"

#include <sys/eventfd.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <memory>

// 防止一个线程创建多个EventLoop   thread_local   就是控制一个线程一个EventLoop
__thread EventLoop *t_loopInThisThread = nullptr;

// 定义默认的Poller IO复用接口的超时时间
const int kPollTimeMs = 10000;

// 创建wakeupfd，用来notify唤醒subLoop处理新来的channel
int createEventfd()
{
    int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); // 函数注释在下面
    if (evtfd < 0)
    {
        LOG_FATAL("eventfd error:%d \n", errno);
    }
    return evtfd;
}

EventLoop::EventLoop()
    : looping_(false)
    , quit_(false)
    , callingPendingFunctors_(false)  // 初始化为没有等待调用的函数
    , threadId_(CurrentThread::tid())  // 获取当前线程ID
    , poller_(Poller::newDefaultPoller(this))  // 创建默认的poller, 参数是this, 因为Channel和Poller都在EventLoop中工作, one loop per thread; 
    , wakeupFd_(createEventfd())  // 创建用于唤醒的eventfd
    , wakeupChannel_(new Channel(this, wakeupFd_))  // 将wakeupFd封装进Channel
{
    LOG_DEBUG("EventLoop created %p in thread %d \n", this, threadId_);
    if (t_loopInThisThread)  // 检查是否已经有EventLoop在这个线程中创建
    {
        LOG_FATAL("Another EventLoop %p exists in this thread %d \n", t_loopInThisThread, threadId_);
    }
    else
    {
        t_loopInThisThread = this;  // 标记当前线程已创建EventLoop
    }

    // 设置当wakeupFd可读时的回调函数
    wakeupChannel_->setReadCallback(std::bind(&EventLoop::handleRead, this));

    // 使wakeupChannel开始监听读事件 （这个是先执行的，再去唤醒！）
    wakeupChannel_->enableReading();
}

EventLoop::~EventLoop()
{
    wakeupChannel_->disableAll();  // 停止所有事件监听
    wakeupChannel_->remove();  // 从Poller中移除此Channel
    ::close(wakeupFd_);  // 关闭wakeup文件描述符
    t_loopInThisThread = nullptr;  // 清除线程中EventLoop的存在标记
}

// 开始事件循环，只应在创建了EventLoop的同一线程中调用
void EventLoop::loop()
{
    looping_ = true;
    quit_ = false;

    LOG_INFO("EventLoop %p start looping \n", this);

    while(!quit_)  // 在没有接收到退出信号时持续运行
    {
        activeChannels_.clear();  // 清空上次活动的channel列表，准备新一轮的poll调用
        // 监听两类fd   一种是client的fd，一种wakeupfd
        pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_);  // epoll_wait() 阻塞等待事件发生; 
        for (Channel *channel : activeChannels_)  // 遍历所有有事件发生的channel
        {
            // 处理每个channel对应的事件
            channel->handleEvent(pollReturnTime_);
        }
        // 执行当前EventLoop事件循环需要处理的回调操作
        /**
         * doPendingFunctors()函数: 
         * 功能: 此部分负责执行所有排队的非I/O任务或回调。这些回调函数可能由其他线程投递给EventLoop，
         *      用于在EventLoop的线程中异步执行。
         * 工作流程：doPendingFunctors会处理一个队列，此队列中包含了其他线程通过runInLoop或queueInLoop方法
         *          提交给EventLoop的任务。这些任务是在EventLoop的控制下执行的，确保了线程安全。
         * 
         * channel->handleEvent(pollReturnTime_) 和 doPendingFunctors()函数 的区别: 
         * 关注点：处理每个Channel对应的事件主要关注于I/O操作（如数据的读写、连接的接受等），
         *        而执行所有待处理的回调函数则更多关注于执行那些需要在事件循环中安全执行的异步或延迟任务。
         * 执行时机：处理Channel事件是响应I/O事件的直接结果，通常是数据到达或发送准备就绪。
         *          而执行回调函数则可能是由内部逻辑触发，如状态变更、定时器超时等。
        */
        doPendingFunctors();
    }

    LOG_INFO("EventLoop %p stop looping. \n", this);
    looping_ = false;  // 标记EventLoop已停止运行
} 

// 退出事件循环  1.loop在自己的线程中调用quit  2.在非loop的线程中，调用loop的quit
/**
 *              mainLoop
 *
 *  subLoop1     subLoop2     subLoop3
 */ 
void EventLoop::quit()
{
    quit_ = true;  // 设置退出标志

    // 如果是在其它线程中，调用的quit   在一个subLoop1中，调用了subLoop2的quit
    // 首先需要先唤醒人家(subLoop2),使其在epoll_wait()上唤醒,向下执行,如果没有任务,在唤醒之前quit已经是true了,
    // 所以while(!quit_)不满足条件关闭事件循环loop(),执行析构函数退出; 
    /*
    bool isInLoopThread() const { return threadId_ ==  CurrentThread::tid(); }
    你想想哈，isInLoopThread()是判断"当前执行的线程"是否是"创建了这个loop的线程(threadId_)"，如果不是的话，就需要
    唤醒可能阻塞在poll_wait上的当前线程，去执行退出；所以要wakeup()啊，通知它！！这时候当前线程的事件循环的quit_
    为true，while(!quit_)就可以退出事件循环了；
    */
    if (!isInLoopThread())  
    {
        wakeup();  // 唤醒正在poll等待的线程
    }
}

// 在当前EventLoop线程中立即执行给定的回调
void EventLoop::runInLoop(Functor cb)
{
    if (isInLoopThread()) // 在当前的EventLoop线程中，执行cb
    {
        cb();
    }
    else // 在非当前loop线程中执行cb , 就需要唤醒loop所在线程，执行cb
    {
        queueInLoop(cb); // 把回调放入队列，并在需要时唤醒EventLoop线程
    }
}

// 把cb放入队列中，唤醒loop所在的线程，执行cb
void EventLoop::queueInLoop(Functor cb)
{
    {
        std::unique_lock<std::mutex> lock(mutex_);
        pendingFunctors_.emplace_back(cb);
    }

    // 唤醒相应的，需要执行上面回调操作的loop的线程了
    /**
    * || callingPendingFunctors_的意思是: 当前loop正在执行回调，也不一定当前线程就必须阻塞在epoll_wait
    * 上，也可能正在执行回调；但是loop又有了新的回调，因为functors.swap(pendingFunctors_), 
    * pendingFunctors_被置空了, 当 当前loop 正在执行回调的时候，当前的loop和其他的loop可以向
    * pendingFunctors_中添加回调, 所以当前的loop又可以执行了, 所以也需要去唤醒;
     */
    if (!isInLoopThread() || callingPendingFunctors_) 
    {
        wakeup(); // 唤醒loop所在线程
    }
}

// 处理wakeup事件，从wakeupFd读取数据，以确保eventfd不会饱和
void EventLoop::handleRead()
{
  uint64_t one = 1;
  ssize_t n = read(wakeupFd_, &one, sizeof one);
  if (n != sizeof one)
  {
    LOG_ERROR("EventLoop::handleRead() reads %lu bytes instead of 8", n);
  }
}

// 用来唤醒loop所在的线程的  向wakeupfd_写一个数据，wakeupChannel就发生读事件，当前loop线程就会被唤醒
void EventLoop::wakeup()
{
    uint64_t one = 1;
    ssize_t n = write(wakeupFd_, &one, sizeof one);
    if (n != sizeof one)
    {
        LOG_ERROR("EventLoop::wakeup() writes %lu bytes instead of 8 \n", n);
    }
}

// EventLoop的方法 =》 Poller的方法
void EventLoop::updateChannel(Channel *channel)
{
    poller_->updateChannel(channel);
}

void EventLoop::removeChannel(Channel *channel)
{
    poller_->removeChannel(channel);
}

bool EventLoop::hasChannel(Channel *channel)
{
    return poller_->hasChannel(channel);
}

// 执行所有挂起的回调函数
void EventLoop::doPendingFunctors()
{
    std::vector<Functor> functors; // 创建临时存放回调的容器
    callingPendingFunctors_ = true;

    {
        std::unique_lock<std::mutex> lock(mutex_); // 加锁
        // 这样可以减少锁的时间, 其他loop可以及时的向pendingFunctors_添加回调了;
        functors.swap(pendingFunctors_);  // 交换回调列表和空容器，快速清空回调列表并减少锁持有时间
    }

    for (const Functor &functor : functors)
    {
        functor(); // 执行当前loop需要执行的回调操作
    }

    callingPendingFunctors_ = false;
}
